package 热题100.滑动窗口.无重复字符的最长子串_3_中等;

import java.util.HashSet;
import java.util.Set;

/*
给定一个字符串 s ，请你找出其中不含有重复字符的最长子串的长度。

示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc"，所以其长度为 3。

示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b"，所以其长度为 1。

示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke"，所以其长度为 3。请注意，你的答案必须是 子串 的长度，"pwke" 是一个子序列，不是子串

思路：
      滑动窗口本质就是有区间的双指针，在右指针移动下一位的过程中出现重复的数时，左指针移动，此时右指针即将指的数字
      可能还是会和区间的数重复，那么左指针会继续移动，在左指针移动的过程中会把元素去除，右指针的移动中会把元素加进去。
      以此来维护左右指针，还是相当于一个固定（左指针），另一个移动（右指针）的双指针。
* */
public class Solution {
    public static void main(String[] args) {
        String s = "bbbbb";
        System.out.println(lengthOfLongestSubstring(s));
    }
    public static int lengthOfLongestSubstring(String s) {
        // set集合是为了判断数字是否重复
        Set<Character> sets = new HashSet<>();
            int ans = 0;
            // 要注意滑动窗口左区间就是i
            int right = -1, n = s.length();
            for (int i = 0; i < n; i ++){
                // 如果不是第一个字母就将左指针移除，注意移除的是前一位
                if (i != 0){
                    sets.remove(s.charAt(i - 1));
                }
                // 如果右指针未到边界且sets集合中没有该元素，说明一直到现在都没有重复的元素，可以一直添加进去
                while (right + 1 < n && !sets.contains(s.charAt(right + 1))){
                    sets.add(s.charAt(right + 1));
                    right ++;
                }
                // 记录满足条件的最大子串，这里的right已经是++过了的，所以长度就是right - i + 1
                ans = Math.max(ans, right - i + 1);
            }
            return ans;
    }
}

